﻿#pragma once

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include "SourceCode/Renderer/EditorCamera.h"
#include "SourceCode/Renderer/Shader.h"
#include "SourceCode/Renderer/Texture.h"
#include "SourceCode/Renderer/SubTexture2D.h"
#include "SourceCode/Renderer/RenderCommand.h"
#include "SourceCode/Renderer/Camera.h"
#include "SourceCode/Renderer/OrthoGraphicCamera.h"

#include "SourceCode/Scene/Components.h"

namespace Hazal
{
	class CRenderer2D
	{
	public:
		/// <summary>
		/// 初始化2D渲染器, 加载长方形VAO
		/// </summary>
		static void Init();

		/// <summary>
		/// 关闭2D渲染器, 清除加载的对象
		/// </summary>
		static void Shutdown();

		/// <summary>
		/// 每帧场景开始
		/// </summary>
		/// <param name="camera">相机</param>
		/// <param name="matTransform">相机变换矩阵</param>
		static void BeginScene(const CCamera& camera, const glm::mat4& matTransform);

		/// <summary>
		/// 每帧编辑场景开始
		/// </summary>
		/// <param name="camera">EditorCamera</param>
		static void BeginScene(const CEditorCamera& camera);

		/// <summary>
		/// 每帧场景开始
		/// </summary>
		/// <param name="camera">正交相机</param>
		static void BeginScene(const COrthoGraphicCamera& camera);

		/// <summary>
		/// 每帧场景结束
		/// </summary>
		static void EndScene();

		/// <summary>
		/// 将每帧的批处理数据传入GPU
		/// </summary>
		static void Flush();

		/// <summary>
		/// 绘制带有大小和位置的矩形
		/// </summary>
		/// <param name="vecPos">位移</param>
		/// <param name="vecSize">缩放</param>
		/// <param name="vecColor">颜色</param>
		static void DrawQuad(const glm::vec2& vecPos, const glm::vec2& vecSize, const glm::vec4& vecColor);

		/// <summary>
		/// 绘制带有大小和位置的矩形
		/// </summary>
		/// <param name="vecPos">位移</param>
		/// <param name="vecSize">缩放</param>
		/// <param name="vecColor">颜色</param>
		static void DrawQuad(const glm::vec3& vecPos, const glm::vec2& vecSize, const glm::vec4& vecColor);

		/// <summary>
		/// 绘制基于变换的矩形
		/// </summary>
		/// <param name="matTransform"></param>
		/// <param name="vecColor"></param>
		static void DrawQuad(const glm::mat4& matTransform, const glm::vec4& vecColor);

		/// <summary>
		/// 绘制带有纹理的矩形
		/// </summary>
		/// <param name="vecPos">位移</param>
		/// <param name="vecSize">缩放</param>
		/// <param name="rTexture">纹理指针</param>
		/// <param name="fTilingFactor">纹理缩放系数</param>
		static void DrawQuad(const glm::vec2& vecPos, const glm::vec2& vecSize, const Ref<CTexture2D>& rTexture, float fTilingFactor = 1.0f);

		/// <summary>
		/// 绘制带有纹理的矩形
		/// </summary>
		/// <param name="vecPos">位移</param>
		/// <param name="vecSize">缩放</param>
		/// <param name="rTexture">纹理指针</param>
		/// <param name="fTilingFactor">纹理缩放系数</param>
		static void DrawQuad(const glm::vec3& vecPos, const glm::vec2& vecSize, const Ref<CTexture2D>& rTexture, float fTilingFactor = 1.0f);

		/// <summary>
		/// 绘制基于变换且带有纹理的矩形
		/// </summary>
		/// <param name="vecPos">位移</param>
		/// <param name="vecSize">缩放</param>
		/// <param name="rTexture">纹理指针</param>
		/// <param name="fTilingFactor">纹理缩放系数</param>
		static void DrawQuad(const glm::mat4& matTransform, const glm::vec4& vecColor, const Ref<CTexture2D>& rTexture, float fTilingFactor = 1.0f);

		/// <summary>
		/// 绘制带有子纹理的矩形
		/// </summary>
		/// <param name="vecPos">位移</param>
		/// <param name="vecSize">缩放</param>
		/// <param name="rSubTexture">子纹理指针</param>
		/// <param name="fTilingFactor">纹理缩放系数</param>
		static void DrawQuad(const glm::vec2& vecPos, const glm::vec2& vecSize, const Ref<CSubTexture2D>& rSubTexture, float fTilingFactor = 1.0f);

		/// <summary>
		/// 绘制带有子纹理的矩形
		/// </summary>
		/// <param name="vecPos">位移</param>
		/// <param name="vecSize">缩放</param>
		/// <param name="rSubTexture">子纹理指针</param>
		/// <param name="fTilingFactor">纹理缩放系数</param>
		static void DrawQuad(const glm::vec3& vecPos, const glm::vec2& vecSize, const Ref<CSubTexture2D>& rSubTexture, float fTilingFactor = 1.0f);

		/// <summary>
		/// 绘制旋转的矩形
		/// </summary>
		/// <param name="vecPos"></param>
		/// <param name="vecSize"></param>
		/// <param name="fRotation"></param>
		/// <param name="vecColor"></param>
		static void DrawRotateQuad(const glm::vec2& vecPos, const glm::vec2& vecSize, float fRotation, const glm::vec4& vecColor);

		/// <summary>
		/// 绘制旋转的矩形
		/// </summary>
		/// <param name="vecPos"></param>
		/// <param name="vecSize"></param>
		/// <param name="fRotation"></param>
		/// <param name="vecColor"></param>
		static void DrawRotateQuad(const glm::vec3& vecPos, const glm::vec2& vecSize, float fRotation, const glm::vec4& vecColor);

		/// <summary>
		/// 绘制带有纹理的可旋转矩形
		/// </summary>
		/// <param name="vecPos"></param>
		/// <param name="vecSize"></param>
		/// <param name="fRotation"></param>
		/// <param name="vecColor"></param>
		/// <param name="rTexture">纹理指针</param>
		/// <param name="fTilingFactor">纹理缩放系数</param>
		static void DrawRotateQuad(const glm::vec2& vecPos, const glm::vec2& vecSize, float fRotation, const Ref<CTexture2D>& rTexture, float fTilingFactor = 1.0f);

		/// <summary>
		/// 绘制带有纹理的可旋转矩形
		/// </summary>
		/// <param name="vecPos"></param>
		/// <param name="vecSize"></param>
		/// <param name="fRotation"></param>
		/// <param name="vecColor"></param>
		/// <param name="rTexture">纹理指针</param>
		/// <param name="fTilingFactor">纹理缩放系数</param>
		static void DrawRotateQuad(const glm::vec3& vecPos, const glm::vec2& vecSize, float fRotation, const Ref<CTexture2D>& rTexture, float fTilingFactor = 1.0f);

		/// <summary>
		/// 绘制带有子纹理的可旋转矩形
		/// </summary>
		/// <param name="vecPos"></param>
		/// <param name="vecSize"></param>
		/// <param name="fRotation"></param>
		/// <param name="vecColor"></param>
		/// <param name="CSubTexture2D">子纹理指针</param>
		/// <param name="fTilingFactor">纹理缩放系数</param>
		static void DrawRotateQuad(const glm::vec2& vecPos, const glm::vec2& vecSize, float fRotation, const Ref<CSubTexture2D>& rSubTexture, float fTilingFactor = 1.0f);

		/// <summary>
		/// 绘制带有子纹理的可旋转矩形
		/// </summary>
		/// <param name="vecPos"></param>
		/// <param name="vecSize"></param>
		/// <param name="fRotation"></param>
		/// <param name="vecColor"></param>
		/// <param name="CSubTexture2D">子纹理指针</param>
		/// <param name="fTilingFactor">纹理缩放系数</param>
		static void DrawRotateQuad(const glm::vec3& vecPos, const glm::vec2& vecSize, float fRotation, const Ref<CSubTexture2D>& rSubTexture, float fTilingFactor = 1.0f);

		/// <summary>
		/// 绘制一个圆
		/// </summary>
		/// <param name="matTransform"></param>
		/// <param name="vecColor"></param>
		/// <param name="fThickness"></param>
		/// <param name="fFade"></param>
		/// <param name="nEntityID"></param>
		static void DrawCircle(const glm::mat4& matTransform, const glm::vec4& vecColor, float fThickness = 1.0f, float fFade = 0.005f, int nEntityID = -1);

		/// <summary>
		/// 绘制编辑模式下的矩形
		/// </summary>
		/// <param name="matTransform">矩形的变换矩阵</param>
		/// <param name="spriteComponent">sprite component</param>
		/// <param name="nEntityID">实体ID</param>
		static void DrawSprite(const glm::mat4& matTransform, SSpriteRendererComponent& spriteComponent, int nEntityID);

		/// <summary>
		/// Render statistics info
		/// </summary>
		struct SStatistics
		{
			uint32_t m_unDrawCall = 0;
			uint32_t m_unQuadCount = 0;

			uint32_t GetTotalVertexCount() { return m_unQuadCount * 4; }
			uint32_t GetTotalIndexCount() { return m_unQuadCount * 6; }
		};

		/// <summary>
		/// Reset render statistics info
		/// </summary>
		static void ResetStats();

		/// <summary>
		/// Get stats info
		/// </summary>
		/// <returns></returns>
		static SStatistics& GetStats();

	private:
		/// <summary>
		/// Draw 4 vertices which compose a quad with counterclockwise order
		/// </summary>
		/// <param name="matTransform">Model matrix</param>
		/// <param name="vecColor">vertex color</param>
		/// <param name="fTextureIdx">texture sampler index</param>
		/// <param name="pVecTexCoord">Texture coords, default(0.0f~1.0f)</param>
		/// <param name="fTilingFactor">Tiling factor</param>
		static void DrawVertices(const glm::mat4& matTransform, const glm::vec4& vecColor, float fTextureIdx, const glm::vec2* pVecTexCoord = nullptr, float fTilingFactor = 1.0f);

		/// <summary>
		/// Flush current draw call, and reset all vars
		/// </summary>
		static void FlushAndReset();

		/// <summary>
		/// Reset render parameters
		/// </summary>
		static void StartBatch();

	};
}
